package org.oimwrapper.connectors.internal;

import Thor.API.*;
import Thor.API.Operations.*;
import com.thortech.util.logging.*;
import com.thortech.xl.dataaccess.*;
import java.util.*;

/**
 * This is provides common functions for lookups.
 * 
 * THIS IS AN INTERNAL CLASS AND SHOULD NOT BE USED DIRECTLY.
 */
public final class OIMLookupUtilities {

	/**
	 * The default logger instance for this instance.
	 */
	private Logger logger;

	/**
	 * The lookup operations instance that backs this object.
	 */
	private tcLookupOperationsIntf lookupOp;
	
	/**
	 * The data provider used by this object.
	 */
	private tcDataProvider database;

	/**
	 * The default constructor.
	 * 
	 * @param ClassLogger The Logger used by the invoking class.
	 * @param LookupOp The lookup operations utility from the invoking class.
	 * @param Database The data provider from the invoking class.
	 */
	protected OIMLookupUtilities(Logger ClassLogger, tcLookupOperationsIntf LookupOp, tcDataProvider Database) {
		logger = ClassLogger;
		lookupOp = LookupOp;
		database = Database;
	}

	/**
	 * Returns a Map containing the attribute names and values from a lookup.  An empty map is returned if the specified lookup
	 * is not found.
	 * 
	 * @param Lookup The name of the lookup to retrieve the values from.
	 * @return A map containing the attribute name value pairs from the specified lookup.
	 * @exception Exception
 	 */
	public Map getLookupValues(String Lookup) throws Exception {
		logger.debug("Entering lookupUtilities.getLookupValues()");
		Map result = new HashMap();
		tcResultSet lookupResults = lookupOp.getLookupValues(Lookup);
		for (int i = 0; i < lookupResults.getRowCount(); i++) {
			lookupResults.goToRow(i);
			String key = lookupResults.getStringValue("Lookup Definition.Lookup Code Information.Code Key");
			String value = lookupResults.getStringValue("Lookup Definition.Lookup Code Information.Decode");
			result.put(key, value);
		}
		logger.debug("Exiting lookupUtilities.getLookupValues()");
		return result;
	}

	/**
	 * Returns the decode value given a lookup and an encode value.   This method ignores case.
	 * 
	 * @param Lookup The name of the lookup to retrieve the value from.
	 * @param Key The name of encode value to retrieve.
	 * @return The corresponding decode value, or an empty string if the specified key or lookup is not found.
	 * @exception Exception
	 */
	public String getLookupValue(String Key, String Lookup) throws Exception {
		logger.debug("Entering lookupUtilities.getLookupValue()");
		String result = "";
		try {
			tcDataSet dataSet = new tcDataSet();
			dataSet.setQuery(database, "select lkv_decoded from lkv inner join lku on lkv.lku_key = lku.lku_key where upper(lkv_encoded) = upper('" + Key.replaceAll("'", "''") + "') and lku_type_string_key = '" + Lookup.replaceAll("'", "''") + "'");
			dataSet.executeQuery();
			tcResultSet results = new tcMetaDataSet(dataSet.getDataSetData(), database);
			if (results.getRowCount() > 0) {
				results.goToRow(0);
				logger.debug(Key + " was found in the lookup table");
				result = results.getStringValue("Lookup Definition.Lookup Code Information.Decode");
			}
		} catch (Exception e) {
			logger.warn("Direct query failed; using slow search -- " + e.getMessage());
			tcResultSet results = lookupOp.getLookupValues(Lookup);
			for (int i = 0; i < results.getRowCount(); i++) {
				results.goToRow(i);
				if (results.getStringValue("Lookup Definition.Lookup Code Information.Code Key").equalsIgnoreCase(Key)) {
					logger.debug(Key + " was found in the lookup table");
					result = results.getStringValue("Lookup Definition.Lookup Code Information.Decode");
					break;
				}
			}
		}
		logger.debug("Exiting lookupUtilities.getLookupValue()");
		return result;
	}
	
	/**
	 * Returns the decode values given a lookup and an decode value.   This method ignores case.
	 * 
	 * @param Lookup The name of the lookup to retrieve the value from.
	 * @param Value The name of decode value to retrieve.
	 * @return The corresponding decode value, or an empty string if the specified key or lookup is not found.
	 * @exception Exception
	 */
	public String[] getLookupKeys(String Value, String Lookup) throws Exception {
		logger.debug("Entering lookupUtilities.getLookupKeys()");
		List result = new ArrayList();
		try {
			tcDataSet dataSet = new tcDataSet();
			dataSet.setQuery(database, "select lkv_encoded from lkv inner join lku on lkv.lku_key = lku.lku_key where upper(lkv_decoded) = upper('" + Value.replaceAll("'", "''") + "') and lku_type_string_key = '" + Lookup.replaceAll("'", "''") + "'");
			dataSet.executeQuery();
			tcResultSet results = new tcMetaDataSet(dataSet.getDataSetData(), database);
			for (int i = 0; i < results.getRowCount(); i++) {
				results.goToRow(i);
				logger.debug(Value + " was found in the lookup table");
				result.add(results.getStringValue("Lookup Definition.Lookup Code Information.Code Key"));
			}
		} catch (Exception e) {
			logger.warn("Direct query failed; using slow search -- " + e.getMessage());
			tcResultSet results = lookupOp.getLookupValues(Lookup);
			for (int i = 0; i < results.getRowCount(); i++) {
				results.goToRow(i);
				if (results.getStringValue("Lookup Definition.Lookup Code Information.Decode").equalsIgnoreCase(Value)) {
					logger.debug(Value + " was found in the lookup table");
					result.add(results.getStringValue("Lookup Definition.Lookup Code Information.Code Key"));
				}
			}
		}
		logger.debug("Exiting lookupUtilities.getLookupKeys()");
		return (String[]) result.toArray(new String[0]);
	}

	/**
	 * Adds a new value to a lookup.
	 * 
	 * @param Lookup The name of the lookup to add the value to.
	 * @param Key The name of the key to add to the lookup.
	 * @param Value the value to add with that key.
	 * @exception Exception
	 */
	public void addLookupValue(String Key, String Value, String Lookup) throws Exception {
		logger.debug("Entering lookupUtilities.addLookupValue()");
		lookupOp.addLookupValue(Lookup, Key, Value, Locale.getDefault().getLanguage(), Locale.getDefault().getCountry());
		logger.debug("Exiting lookupUtilities.addLookupValue()");
	}
	
	/**
	 * Updates a value within a lookup.
	 * 
	 * @param Key The name of the key to update in the lookup.
	 * @param Value The new value to set for that key.
	 * @param Lookup The name of the lookup to update the value in.
	 * @param ExactMatch <code>true</code> if an exact case match should be used, or
	 *                   <code>false</code> if a case-insensitive match should be used.
	 * @exception Exception
	 */
	public void updateLookupValue(String Key, String Value, String Lookup, boolean ExactMatch) throws Exception {
		logger.debug("Entering lookupUtilities.updateLookupValue()");
		removeLookupValue(Key, Lookup, ExactMatch);
		addLookupValue(Key, Value, Lookup);
		logger.debug("Exiting lookupUtilities.updateLookupValue()");
	}

	/**
	 * Removes a value from a lookup.
	 * 
	 * @param Lookup The name of the lookup to remove the value from.
	 * @param Key The name of the key to remove from the lookup.
	 * @param ExactMatch <code>true</code> if an exact case match should be used, or
	 *                   <code>false</code> if a case-insensitive match should be used.
	 * @exception Exception
	 */
	public void removeLookupValue(String Key, String Lookup, boolean ExactMatch) throws Exception {
		logger.debug("Entering lookupUtilities.removeLookupValue()");
		Map searchFor = new HashMap();
		searchFor.put("Lookup Definition.Lookup Code Information.Code Key", Key);
		tcResultSet results = lookupOp.getLookupValues(Lookup, searchFor);
		for (int i = 0; i < results.getRowCount(); i++) {
			results.goToRow(i);
			String key = results.getStringValue("Lookup Definition.Lookup Code Information.Code Key");
			if (!ExactMatch && key.equalsIgnoreCase(Key)) {
				lookupOp.removeLookupValue(Lookup, key);
			} else if (ExactMatch && key.equals(Key)) {
				lookupOp.removeLookupValue(Lookup, key);
			}
		}
		logger.debug("Exiting lookupUtilities.removeLookupValue()");
	}
	
	/**
	 * Creates a new lookup.
	 * 
	 * @param Lookup The name of the lookup to create.
	 * @exception Exception
	 */
	public void createLookup(String Lookup) throws Exception {
		logger.debug("Entering lookupUtilities.createLookup()");
		tcDataSet dataSet = new tcDataSet();
		dataSet.setQuery(database, "select lku_key from lku where lku_type_string_key = '" + Lookup.replaceAll("'", "''") + "'");
		dataSet.executeQuery();
		if (dataSet.getDataSetData().inTotalRows == 0) {
			lookupOp.addLookupCode(Lookup);
		}
		logger.debug("Exiting lookupUtilities.createLookup()");
	}
	
	/**
	 * Removes all existing values from a lookup.
	 * 
	 * @param Lookup The name of the lookup to remove all existing values from.
	 * @exception Exception
	 */
	public void clearLookup(String Lookup) throws Exception {
		logger.debug("Entering lookupUtilities.clearLookup()");
		tcResultSet results = lookupOp.getLookupValues(Lookup);
		for (int i = 0; i < results.getRowCount(); i++) {
			results.goToRow(i);
			String key = results.getStringValue("Lookup Definition.Lookup Code Information.Code Key");
			lookupOp.removeLookupValue(Lookup, key);
		}
		logger.debug("Exiting lookupUtilities.clearLookup()");
	}
	
	/**
	 * Removes an existing lookup, including any data within.
	 * 
	 * @param Lookup The name of the lookup to remove.
	 * @exception Exception
	 */
	public void removeLookup(String Lookup) throws Exception {
		logger.debug("Entering lookupUtilities.removeLookup()");
		clearLookup(Lookup);
		lookupOp.removeLookupCode(Lookup);
		logger.debug("Exiting lookupUtilities.removeLookup()");
	}
}